<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>call、apply和bind</title>
</head>

<body>
  <script>
    function func(x, y) {
      console.log(this, x, y);
    }
    let obj = {
      name: 'OBJ'
    };

    /**
     * 原理：利用“点”定this机制，context.xxx = self 例如“obj.xxx = func” =>obj.xxx();
     **/
    Function.prototype.call = function call(context, ...params) {
      // this/self->func  context->obj params->[10,20]
      console.log(context);
      if (typeof context === 'undefined' || context === null) {
        context = window
      }
      // context == null ? context = window : null;
      // 判断普通类型加属性，输出为undefined 如 "1".number = 10  "1".number 输出为undefined
      // !/^(object|function)$/i.test(typeof context) ? context = Object(context) : null;
      let self = this, result;
      // 给obj即context添加唯一属性值，这里我们使用了Symbol
      let key = Symbol('KEY');
      context[key] = self;
      // 执行func,并将结果存储，最后返回。
      result = context[key](...params);
      delete context[key];
      return result;
    }
    // func.call(obj, 10, 20);

    Function.prototype.apply = function apply(context, params) {
      // this/self->func  context->obj params->[10,20]
      console.log(context);
      if (typeof context === 'undefined' || context === null) {
        context = window
      }
      // context == null ? context = window : null;
      // !/^(object|function)$/i.test(typeof context) ? context = Object(context) : null;
      let self = this, result;
      // 给obj即context添加唯一属性值，这里我们使用了Symbol
      let key = Symbol('KEY');
      context[key] = self;
      // 执行func,并将结果存储，最后返回。
      result = context[key](...params);
      delete context[key];
      return result;
    }

    // func.apply(obj, [10, 20]);

    Function.prototype.bind = function bind(context, ...params) {
      // this/self->func  context->obj params->[10,20]
      console.log(context);
      if (typeof context === 'undefined' || context === null) {
        context = window
      };
      self = this;
      // 把func执行并且改变this即可  args->是执行proxy的时候可能传递的值
      return function proxy(...args) {
        self.apply(context, params.concat(args));
      };
    }


    Function.prototype.myBind = function bind(context, ...params) {
      // this/self->func  context->obj params->[10,20]
      console.log(context);
      if (typeof context === 'undefined' || context === null) {
        context = window
      };
      let self = this;
      // 根据调用方式，传入不同绑定值
      return function Fn(...args) {
        return self.apply(this instanceof Fn ? new fn(...params) : context, params.concat(args));
      };
    }


    document.body.addEventListener('click', func.bind(obj, 10, 20));
    // document.body.addEventListener('click', proxy)


    // 跨域设置

    var http = require('http');
    var server = http.createServer();
    var qs = require('querystring');

    server.on('request', function (req, res) {
      var postData = '';

      // 数据块接收中
      req.addListener('data', function (chunk) {
        postData += chunk;
      });

      // 数据接收完毕
      req.addListener('end', function () {
        postData = qs.parse(postData);

        // 跨域后台设置
        res.writeHead(200, {
          'Access-Control-Allow-Credentials': 'true',     // 后端允许发送Cookie
          'Access-Control-Allow-Origin': 'http://www.domain1.com',    // 允许访问的域（协议+域名+端口）
          /* 
           * 此处设置的cookie还是domain2的而非domain1，因为后端也不能跨域写cookie(nginx反向代理可以实现)，
           * 但只要domain2中写入一次cookie认证，后面的跨域接口都能从domain2中获取cookie，从而实现所有的接口都能跨域访问
           */
          'Set-Cookie': 'l=a123456;Path=/;Domain=www.domain2.com;HttpOnly'  // HttpOnly的作用是让js无法读取cookie
        });

        res.write(JSON.stringify(postData));
        res.end();
      });
    });

    server.listen('8080');
    console.log('Server is running at port 8080...');
  </script>
</body>

</html>